From 86118fbdbafe6af54b2da467e1073c49e1742116 Mon Sep 17 00:00:00 2001
From: hjl <hjl@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Tue, 16 Jan 2018 11:17:49 +0000
Subject: [PATCH 7/9] x86: Add -mindirect-branch-register

Add -mindirect-branch-register to force indirect branch via register.
This is implemented by disabling patterns of indirect branch via memory,
similar to TARGET_X32.

-mindirect-branch= and -mfunction-return= tests are updated with
-mno-indirect-branch-register to avoid false test failures when
-mindirect-branch-register is added to RUNTESTFLAGS for "make check".

gcc/

	Backport from mainline
	2018-01-14  H.J. Lu  <hongjiu.lu@intel.com>

	* config/i386/constraints.md (Bs): Disallow memory operand for
	-mindirect-branch-register.
	(Bw): Likewise.
	* config/i386/predicates.md (indirect_branch_operand): Likewise.
	(GOT_memory_operand): Likewise.
	(call_insn_operand): Likewise.
	(sibcall_insn_operand): Likewise.
	(GOT32_symbol_operand): Likewise.
	* config/i386/i386.md (indirect_jump): Call convert_memory_address
	for -mindirect-branch-register.
	(tablejump): Likewise.
	(*sibcall_memory): Likewise.
	(*sibcall_value_memory): Likewise.
	Disallow peepholes of indirect call and jump via memory for
	-mindirect-branch-register.
	(*call_pop): Replace m with Bw.
	(*call_value_pop): Likewise.
	(*sibcall_pop_memory): Replace m with Bs.
	* config/i386/i386.opt (mindirect-branch-register): New option.
	* doc/invoke.texi: Document -mindirect-branch-register option.

gcc/testsuite/

	Backport from mainline
	2018-01-14  H.J. Lu  <hongjiu.lu@intel.com>

	* gcc.target/i386/indirect-thunk-1.c (dg-options): Add
	-mno-indirect-branch-register.
	* gcc.target/i386/indirect-thunk-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-3.c: Likewise.
	* gcc.target/i386/indirect-thunk-4.c: Likewise.
	* gcc.target/i386/indirect-thunk-5.c: Likewise.
	* gcc.target/i386/indirect-thunk-6.c: Likewise.
	* gcc.target/i386/indirect-thunk-7.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-1.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-3.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-4.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-5.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-6.c: Likewise.
	* gcc.target/i386/indirect-thunk-attr-7.c: Likewise.
	* gcc.target/i386/indirect-thunk-bnd-1.c: Likewise.
	* gcc.target/i386/indirect-thunk-bnd-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-bnd-3.c: Likewise.
	* gcc.target/i386/indirect-thunk-bnd-4.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-1.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-3.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-4.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-5.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-6.c: Likewise.
	* gcc.target/i386/indirect-thunk-extern-7.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-1.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-3.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-4.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-5.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-6.c: Likewise.
	* gcc.target/i386/indirect-thunk-inline-7.c: Likewise.
	* gcc.target/i386/ret-thunk-10.c: Likewise.
	* gcc.target/i386/ret-thunk-11.c: Likewise.
	* gcc.target/i386/ret-thunk-12.c: Likewise.
	* gcc.target/i386/ret-thunk-13.c: Likewise.
	* gcc.target/i386/ret-thunk-14.c: Likewise.
	* gcc.target/i386/ret-thunk-15.c: Likewise.
	* gcc.target/i386/ret-thunk-9.c: Likewise.
	* gcc.target/i386/indirect-thunk-register-1.c: New test.
	* gcc.target/i386/indirect-thunk-register-2.c: Likewise.
	* gcc.target/i386/indirect-thunk-register-3.c: Likewise.

i386: Rename to ix86_indirect_branch_register

Rename the variable for -mindirect-branch-register to
ix86_indirect_branch_register to match the command-line option name.

	Backport from mainline
	2018-01-15  H.J. Lu  <hongjiu.lu@intel.com>

	* config/i386/constraints.md (Bs): Replace
	ix86_indirect_branch_thunk_register with
	ix86_indirect_branch_register.
	(Bw): Likewise.
	* config/i386/i386.md (indirect_jump): Likewise.
	(tablejump): Likewise.
	(*sibcall_memory): Likewise.
	(*sibcall_value_memory): Likewise.
	Peepholes of indirect call and jump via memory: Likewise.
	* config/i386/i386.opt: Likewise.
	* config/i386/predicates.md (indirect_branch_operand): Likewise.
	(GOT_memory_operand): Likewise.
	(call_insn_operand): Likewise.
	(sibcall_insn_operand): Likewise.
	(GOT32_symbol_operand): Likewise.

x86: Rewrite ix86_indirect_branch_register logic

Rewrite ix86_indirect_branch_register logic with

(and (not (match_test "ix86_indirect_branch_register"))
     (original condition before r256662))

	Backport from mainline
	2018-01-15  H.J. Lu  <hongjiu.lu@intel.com>

	* config/i386/predicates.md (constant_call_address_operand):
	Rewrite ix86_indirect_branch_register logic.
	(sibcall_insn_operand): Likewise.

Don't check ix86_indirect_branch_register for GOT operand

Since GOT_memory_operand and GOT32_symbol_operand are simple pattern
matches, don't check ix86_indirect_branch_register here.  If needed,
-mindirect-branch= will convert indirect branch via GOT slot to a call
and return thunk.

	Backport from mainline
	2018-01-15  H.J. Lu  <hongjiu.lu@intel.com>

	* config/i386/constraints.md (Bs): Update
	ix86_indirect_branch_register check.  Don't check
	ix86_indirect_branch_register with GOT_memory_operand.
	(Bw): Likewise.
	* config/i386/predicates.md (GOT_memory_operand): Don't check
	ix86_indirect_branch_register here.
	(GOT32_symbol_operand): Likewise.

i386: Rewrite indirect_branch_operand logic

	Backport from mainline
	2018-01-15  H.J. Lu  <hongjiu.lu@intel.com>

	* config/i386/predicates.md (indirect_branch_operand): Rewrite
	ix86_indirect_branch_register logic.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256735 138bc75d-0d04-0410-961f-82ee72b054a4

[Ubuntu note: Dropped indirect-thunk-5.c, indirect-thunk-6.c,
 indirect-thunk-bnd-3.c, indirect-thunk-bnd-4.c,
 indirect-thunk-extern-5.c, indirect-thunk-extern-6.c,
 indirect-thunk-inline-5.c, and indirect-thunk-inline-6.c tests due
 to gcc 5.4 and earlier not supporting the -fno-plt option.
	--sbeattie,]
---
 src/gcc/config/i386/constraints.md                            |    6 +
 src/gcc/config/i386/i386.md                                   |   34 ++++++----
 src/gcc/config/i386/i386.opt                                  |    4 +
 src/gcc/config/i386/predicates.md                             |    9 +-
 src/gcc/doc/invoke.texi                                       |    7 +-
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c          |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c          |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c          |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c          |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c          |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c     |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c      |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c      |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c   |    2 
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c |   22 ++++++
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c |   20 +++++
 src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c |   19 +++++
 src/gcc/testsuite/gcc.target/i386/ret-thunk-10.c              |    2 
 src/gcc/testsuite/gcc.target/i386/ret-thunk-11.c              |    2 
 src/gcc/testsuite/gcc.target/i386/ret-thunk-12.c              |    2 
 src/gcc/testsuite/gcc.target/i386/ret-thunk-13.c              |    2 
 src/gcc/testsuite/gcc.target/i386/ret-thunk-14.c              |    2 
 src/gcc/testsuite/gcc.target/i386/ret-thunk-15.c              |    2 
 src/gcc/testsuite/gcc.target/i386/ret-thunk-9.c               |    2 
 39 files changed, 134 insertions(+), 49 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c

Index: b/src/gcc/config/i386/constraints.md
===================================================================
--- a/src/gcc/config/i386/constraints.md
+++ b/src/gcc/config/i386/constraints.md
@@ -157,12 +157,14 @@
 
 (define_constraint "Bs"
   "@internal Sibcall memory operand."
-  (and (not (match_test "TARGET_X32"))
+  (and (not (match_test "ix86_indirect_branch_register"))
+       (not (match_test "TARGET_X32"))
        (match_operand 0 "sibcall_memory_operand")))
 
 (define_constraint "Bw"
   "@internal Call memory operand."
-  (and (not (match_test "TARGET_X32"))
+  (and (not (match_test "ix86_indirect_branch_register"))
+       (not (match_test "TARGET_X32"))
        (match_operand 0 "memory_operand")))
 
 (define_constraint "Bz"
Index: b/src/gcc/config/i386/i386.md
===================================================================
--- a/src/gcc/config/i386/i386.md
+++ b/src/gcc/config/i386/i386.md
@@ -11554,7 +11554,7 @@
   [(set (pc) (match_operand 0 "indirect_branch_operand"))]
   ""
 {
-  if (TARGET_X32)
+  if (TARGET_X32 || ix86_indirect_branch_register)
     operands[0] = convert_memory_address (word_mode, operands[0]);
   cfun->machine->has_local_indirect_jump = true;
 })
@@ -11607,7 +11607,7 @@
 					 OPTAB_DIRECT);
     }
 
-  if (TARGET_X32)
+  if (TARGET_X32 || ix86_indirect_branch_register)
     operands[0] = convert_memory_address (word_mode, operands[0]);
   cfun->machine->has_local_indirect_jump = true;
 })
@@ -11764,7 +11764,7 @@
   [(call (mem:QI (match_operand:W 0 "memory_operand" "m"))
 	 (match_operand 1))
    (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
-  "!TARGET_X32"
+  "!TARGET_X32 && !ix86_indirect_branch_register"
   "* return ix86_output_call_insn (insn, operands[0]);"
   [(set_attr "type" "call")])
 
@@ -11773,7 +11773,9 @@
 	(match_operand:W 1 "memory_operand"))
    (call (mem:QI (match_dup 0))
 	 (match_operand 3))]
-  "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
+  "!TARGET_X32
+   && !ix86_indirect_branch_register
+   && SIBLING_CALL_P (peep2_next_insn (1))
    && peep2_reg_dead_p (2, operands[0])"
   [(parallel [(call (mem:QI (match_dup 1))
 		    (match_dup 3))
@@ -11785,7 +11787,9 @@
    (unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
    (call (mem:QI (match_dup 0))
 	 (match_operand 3))]
-  "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
+  "!TARGET_X32
+   && !ix86_indirect_branch_register
+   && SIBLING_CALL_P (peep2_next_insn (2))
    && peep2_reg_dead_p (3, operands[0])"
   [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
    (parallel [(call (mem:QI (match_dup 1))
@@ -11806,7 +11810,7 @@
 })
 
 (define_insn "*call_pop"
-  [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lmBz"))
+  [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lBwBz"))
 	 (match_operand 1))
    (set (reg:SI SP_REG)
 	(plus:SI (reg:SI SP_REG)
@@ -11826,7 +11830,7 @@
   [(set_attr "type" "call")])
 
 (define_insn "*sibcall_pop_memory"
-  [(call (mem:QI (match_operand:SI 0 "memory_operand" "m"))
+  [(call (mem:QI (match_operand:SI 0 "memory_operand" "Bs"))
 	 (match_operand 1))
    (set (reg:SI SP_REG)
 	(plus:SI (reg:SI SP_REG)
@@ -11878,7 +11882,9 @@
   [(set (match_operand:W 0 "register_operand")
         (match_operand:W 1 "memory_operand"))
    (set (pc) (match_dup 0))]
-  "!TARGET_X32 && peep2_reg_dead_p (2, operands[0])"
+  "!TARGET_X32
+   && !ix86_indirect_branch_register
+   && peep2_reg_dead_p (2, operands[0])"
   [(set (pc) (match_dup 1))])
 
 ;; Call subroutine, returning value in operand 0
@@ -11928,7 +11934,7 @@
  	(call (mem:QI (match_operand:W 1 "memory_operand" "m"))
 	      (match_operand 2)))
    (unspec [(const_int 0)] UNSPEC_PEEPSIB)]
-  "!TARGET_X32"
+  "!TARGET_X32 && !ix86_indirect_branch_register"
   "* return ix86_output_call_insn (insn, operands[1]);"
   [(set_attr "type" "callv")])
 
@@ -11938,7 +11944,9 @@
    (set (match_operand 2)
    (call (mem:QI (match_dup 0))
 		 (match_operand 3)))]
-  "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (1))
+  "!TARGET_X32
+   && !ix86_indirect_branch_register
+   && SIBLING_CALL_P (peep2_next_insn (1))
    && peep2_reg_dead_p (2, operands[0])"
   [(parallel [(set (match_dup 2)
 		   (call (mem:QI (match_dup 1))
@@ -11952,7 +11960,9 @@
    (set (match_operand 2)
 	(call (mem:QI (match_dup 0))
 	      (match_operand 3)))]
-  "!TARGET_X32 && SIBLING_CALL_P (peep2_next_insn (2))
+  "!TARGET_X32
+   && !ix86_indirect_branch_register
+   && SIBLING_CALL_P (peep2_next_insn (2))
    && peep2_reg_dead_p (3, operands[0])"
   [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)
    (parallel [(set (match_dup 2)
@@ -11976,7 +11986,7 @@
 
 (define_insn "*call_value_pop"
   [(set (match_operand 0)
-	(call (mem:QI (match_operand:SI 1 "call_insn_operand" "lmBz"))
+	(call (mem:QI (match_operand:SI 1 "call_insn_operand" "lBwBz"))
 	      (match_operand 2)))
    (set (reg:SI SP_REG)
 	(plus:SI (reg:SI SP_REG)
Index: b/src/gcc/config/i386/i386.opt
===================================================================
--- a/src/gcc/config/i386/i386.opt
+++ b/src/gcc/config/i386/i386.opt
@@ -900,3 +900,7 @@ Enum(indirect_branch) String(thunk-inlin
 
 EnumValue
 Enum(indirect_branch) String(thunk-extern) Value(indirect_branch_thunk_extern)
+
+mindirect-branch-register
+Target Report Var(ix86_indirect_branch_register) Init(0)
+Force indirect call and jump via register.
Index: b/src/gcc/config/i386/predicates.md
===================================================================
--- a/src/gcc/config/i386/predicates.md
+++ b/src/gcc/config/i386/predicates.md
@@ -607,7 +607,8 @@
 ;; Test for a valid operand for indirect branch.
 (define_predicate "indirect_branch_operand"
   (ior (match_operand 0 "register_operand")
-       (and (not (match_test "TARGET_X32"))
+       (and (not (match_test "ix86_indirect_branch_register"))
+	    (not (match_test "TARGET_X32"))
 	    (match_operand 0 "memory_operand"))))
 
 ;; Test for a valid operand for a call instruction.
@@ -616,7 +617,8 @@
   (ior (match_test "constant_call_address_operand
 		     (op, mode == VOIDmode ? mode : Pmode)")
        (match_operand 0 "call_register_no_elim_operand")
-       (and (not (match_test "TARGET_X32"))
+       (and (not (match_test "ix86_indirect_branch_register"))
+	    (not (match_test "TARGET_X32"))
 	    (match_operand 0 "memory_operand"))))
 
 ;; Similarly, but for tail calls, in which we cannot allow memory references.
@@ -624,7 +626,8 @@
   (ior (match_test "constant_call_address_operand
 		     (op, mode == VOIDmode ? mode : Pmode)")
        (match_operand 0 "register_no_elim_operand")
-       (and (not (match_test "TARGET_X32"))
+       (and (not (match_test "ix86_indirect_branch_register"))
+	    (not (match_test "TARGET_X32"))
 	    (match_operand 0 "sibcall_memory_operand"))))
 
 ;; Match exactly zero.
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-3.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-7.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
 
 void func0 (void);
 void func1 (void);
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-3.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-5.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-6.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-attr-7.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -fno-pic" } */
 
 void func0 (void);
 void func1 (void);
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { ! x32 } } } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
 
 void (*dispatch) (char *);
 char buf[10];
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-bnd-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile { target { ! x32 } } } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fcheck-pointer-bounds -mmpx -fno-pic" } */
 
 void (*dispatch) (char *);
 char buf[10];
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-3.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-extern-7.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
 
 void func0 (void);
 void func1 (void);
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-3.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
 
 typedef void (*dispatch_t)(long offset);
 
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-inline-7.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
 
 void func0 (void);
 void func1 (void);
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
===================================================================
--- /dev/null
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk -mindirect-branch-register -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
+/* { dg-final { scan-assembler {\tpause} } } */
+/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch"  } } */
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk\n" } } */
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk_bnd\n" } } */
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
===================================================================
--- /dev/null
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk-inline -mindirect-branch-register -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "call\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler "mov\[ \t\](%eax|%rax), \\((%esp|%rsp)\\)" } } */
+/* { dg-final { scan-assembler {\tpause} } } */
+/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch"  } } */
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
+/* { dg-final { scan-assembler-not "__x86_indirect_thunk" } } */
Index: b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
===================================================================
--- /dev/null
+++ b/src/gcc/testsuite/gcc.target/i386/indirect-thunk-register-3.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mindirect-branch=thunk-extern -mindirect-branch-register -fno-pic" } */
+
+typedef void (*dispatch_t)(long offset);
+
+dispatch_t dispatch;
+
+void
+male_indirect_jump (long offset)
+{
+  dispatch(offset);
+}
+
+/* { dg-final { scan-assembler "jmp\[ \t\]*__x86_indirect_thunk_(r|e)ax" } } */
+/* { dg-final { scan-assembler-not "push(?:l|q)\[ \t\]*_?dispatch"  } } */
+/* { dg-final { scan-assembler-not "pushq\[ \t\]%rax" } } */
+/* { dg-final { scan-assembler-not {\t(pause|pause|nop)} } } */
+/* { dg-final { scan-assembler-not "jmp\[ \t\]*\.LIND" } } */
+/* { dg-final { scan-assembler-not "call\[ \t\]*\.LIND" } } */
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-10.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk-inline -mindirect-branch=thunk -fno-pic" } */
 
 extern void (*bar) (void);
 
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-11.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk-extern -mindirect-branch=thunk -fno-pic" } */
 
 extern void (*bar) (void);
 
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-12.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk -fno-pic" } */
 
 extern void (*bar) (void);
 
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-13.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-inline -fno-pic" } */
 
 extern void (*bar) (void);
 extern int foo (void) __attribute__ ((function_return("thunk")));
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-14.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=thunk-extern -fno-pic" } */
 
 extern void (*bar) (void);
 
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-15.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=keep -mindirect-branch=keep -fno-pic" } */
 
 extern void (*bar) (void);
 
Index: b/src/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
===================================================================
--- a/src/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
+++ b/src/gcc/testsuite/gcc.target/i386/ret-thunk-9.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
+/* { dg-options "-O2 -mno-indirect-branch-register -mno-indirect-branch-register -mfunction-return=thunk -mindirect-branch=thunk -fno-pic" } */
 
 extern void (*bar) (void);
 
